/*
*  Copyright 2019-2020 Zheng Jie
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*  http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/
package me.zhengjie.modules.gis.service.impl;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.modules.gis.domain.TimeLine;
import me.zhengjie.utils.*;
import lombok.RequiredArgsConstructor;
import me.zhengjie.modules.gis.repository.TimeLineRepository;
import me.zhengjie.modules.gis.service.TimeLineService;
import me.zhengjie.modules.gis.service.dto.TimeLineDto;
import me.zhengjie.modules.gis.service.dto.TimeLineQueryCriteria;
import me.zhengjie.modules.gis.service.mapstruct.TimeLineMapper;
import me.zhengjie.utils.map.LonlatConver;
import net.dreamlu.mica.core.result.R;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.util.*;
import java.io.IOException;
import javax.servlet.http.HttpServletResponse;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
* @website https://el-admin.vip
* @description 服务实现
* @author ZhuangBing Yan
* @date 2022-08-19
**/
@Service
@RequiredArgsConstructor
@CacheConfig(cacheNames = "timeLine")
@Slf4j
public class TimeLineServiceImpl implements TimeLineService {

    private final TimeLineRepository timeLineRepository;
    private final TimeLineMapper timeLineMapper;


    private final BigDecimal[]  areaPoint =  new BigDecimal[]{new BigDecimal("120.849395"),new BigDecimal("31.337257")};
    private final String DESTINATION = "120.849395,31.337257";

    private final String MASTER = "120.45160700,31.39679000";
    @Override
    public Map<String,Object> queryAll(TimeLineQueryCriteria criteria, Pageable pageable){
        Page<TimeLine> page = timeLineRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable);
        return PageUtil.toPage(page.map(timeLineMapper::toDto));
    }

    @Override
    public List<TimeLineDto> queryAll(TimeLineQueryCriteria criteria){
        return timeLineMapper.toDto(timeLineRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder)));
    }

    @Override
    @Transactional
    public TimeLineDto findById(Long id) {
        TimeLine timeLine = timeLineRepository.findById(id).orElseGet(TimeLine::new);
        ValidationUtil.isNull(timeLine.getId(),"TimeLine","id",id);
        return timeLineMapper.toDto(timeLine);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public TimeLineDto create(TimeLine resources) {
        Snowflake snowflake = IdUtil.createSnowflake(1, 1);
        resources.setId(snowflake.nextId()); 
        return timeLineMapper.toDto(timeLineRepository.save(resources));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(TimeLine resources) {
        TimeLine timeLine = timeLineRepository.findById(resources.getId()).orElseGet(TimeLine::new);
        ValidationUtil.isNull( timeLine.getId(),"TimeLine","id",resources.getId());
        timeLine.copy(resources);
        timeLineRepository.save(timeLine);
    }

    @Override
    public void deleteAll(Long[] ids) {
        for (Long id : ids) {
            timeLineRepository.deleteById(id);
        }
    }

    @Override
    public void download(List<TimeLineDto> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (TimeLineDto timeLine : all) {
            Map<String,Object> map = new LinkedHashMap<>();
            map.put("进厂时间", timeLine.getEnterInTime());
            map.put("路经线坐标", timeLine.getLinePosition());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    @Override
    @Cacheable(key = "'enterInTime:' + #enterInTime")
    public List<TimeLineDto> findByEnterTimeLimit(String enterInTime, Pageable pageable) {
        return timeLineMapper.toDto(timeLineRepository.findAll());
//        Page<TimeLine> page = timeLineRepository.findByEnterTimeLimit(enterInTime,pageable);
//        return PageUtil.toPage(page.map(timeLineMapper::toDto));
    }

    @Override
    @Cacheable(key = "'distinctLine:' + #enterInTime")
    public List<List<BigDecimal[]>> findDistinctLine(String enterInTime) {
        //
        List<List<BigDecimal[]>> collect = timeLineRepository.findDistinctLine(enterInTime).stream().map(res -> {
            List<BigDecimal[]> parseArray1 = JSONArray.parseArray(res, BigDecimal[].class);
            List<BigDecimal[]> result  = new ArrayList<>();
            parseArray1.forEach(ele ->{
                double[] doubles = LonlatConver.gcj02_To_Wgs84(ele[0].doubleValue(), ele[1].doubleValue());
                result.add(new BigDecimal[]{new BigDecimal(doubles[0]+""),new BigDecimal(doubles[1]+"")});
            });
            return result;
        }).collect(Collectors.toList());
        return collect;
    }

    @Override
    @Cacheable(key = "'CurrentMonth:' + #enterInTime")
    public List<ConcurrentHashMap<String, Object>> findCurrentMonth(String enterInTime) {
        List<ConcurrentHashMap<String,Object>> collect = timeLineRepository.findCurrentMonth(enterInTime).stream().map(res -> {
            List<BigDecimal[]> parseArray1 = JSONArray.parseArray(res.get("linePosition").toString(), BigDecimal[].class);
            ConcurrentHashMap<String,Object> parm = new ConcurrentHashMap<>(2);
            List<BigDecimal[]> result  = new ArrayList<>();
            parseArray1.forEach(ele ->{
                double[] doubles = LonlatConver.gcj02_To_Wgs84(ele[0].doubleValue(), ele[1].doubleValue());
                result.add(new BigDecimal[]{new BigDecimal(doubles[0]+""),new BigDecimal(doubles[1]+"")});
            });
            parm.put("linePosition",result);
            parm.put("weight",res.get("weight").toString());
            return parm;
        }).collect(Collectors.toList());
        return collect;
    }

    @Override
    @Cacheable(key = "'OneAre:' + #enterInTime")
    public List<List<BigDecimal[]>> findOneAre(String enterInTime) {
        BigDecimal minlng = new BigDecimal("120.6863359794");
        BigDecimal maxlng = new BigDecimal("120.8365687032");
        BigDecimal minlat = new BigDecimal("31.3048179341");
        BigDecimal maxlat = new BigDecimal("31.3562680831");
        List<List<BigDecimal[]>> reslut = new ArrayList<>();
        RestTemplate restTemplate = new RestTemplate();
        for(int i = 0;i<80;i++){
            BigDecimal lng = RandomUtil.randomBigDecimal(minlng, maxlng);
            BigDecimal lat = RandomUtil.randomBigDecimal(minlat, maxlat);
            String origin = lng+","+lat;
            //换取参数
            ResponseEntity<String> forEntity = restTemplate.getForEntity("https://restapi.amap.com/v5/direction/driving?" +
                            "key=a55d9d3ac4c5c777f76415b080f76000" +
                            "&origin=" + origin+
                            "&destination="+DESTINATION+
                            "&strategy=35,0,37"+//速度优先
                            "&show_fields=polyline"
                    , String.class);
            if(Integer.valueOf(200).equals(forEntity.getStatusCodeValue())){
                String body = forEntity.getBody();
                JSONObject res = JSONObject.parseObject(body, JSONObject.class);
                if(res != null && StringUtils.equals("1", res.getString("status"))) {
                    //表示查询结果正常了，接下来做处理
                    if("1".equals(res.getString("count"))){
                        //表述这有确切的地点
                        String route = res.getString("route");
                        JSONObject routeArray = JSONObject.parseObject(route, JSONObject.class);
                        List<BigDecimal[]> linePoint = new ArrayList<>();
                        String paths = routeArray.getString("paths");
                        List<JSONObject> pathArray = JSONArray.parseArray(paths,JSONObject.class);
                        JSONObject jsonPath = pathArray.get(0);
                        String steps = jsonPath.getString("steps");
                        List<JSONObject> stepsArray = JSONArray.parseArray(steps,JSONObject.class);
                        for(JSONObject ele:stepsArray){
                            String polylineStr = ele.getString("polyline");
                            String[] split = polylineStr.split(";");
                            for(String str :split){
                                 String[] position = str.split(",");
                                linePoint.add(new BigDecimal[]{new BigDecimal(position[0]),new BigDecimal(position[1])});
                            }
                        }
                        log.info("当前路径坐标{}",linePoint);
                        List<BigDecimal[]> pam = new ArrayList<>();
                        linePoint.forEach(ele ->{
                            double[] doubles = LonlatConver.gcj02_To_Wgs84(ele[0].doubleValue(), ele[1].doubleValue());
                            pam.add(new BigDecimal[]{new BigDecimal(doubles[0]+""),new BigDecimal(doubles[1]+"")});
                        });
                        reslut.add(pam);
                    }
                }
            }
        }
        return reslut;

    }

    @Override
    @Cacheable(key = "'MasterArea:' + #enterInTime")
    public List<BigDecimal[]> findMasterArea(String enterInTime) {
        List<BigDecimal[]> pam = new ArrayList<>();
        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<String> forEntity = restTemplate.getForEntity("https://restapi.amap.com/v5/direction/driving?" +
                        "key=a55d9d3ac4c5c777f76415b080f76000" +
                        "&origin=" + DESTINATION+
                        "&destination="+MASTER+
                        "&strategy=0"+//速度优先
                        "&show_fields=polyline"
                , String.class);
        if(new Integer(200).equals(forEntity.getStatusCodeValue())){
            String body = forEntity.getBody();
            JSONObject res = JSONObject.parseObject(body, JSONObject.class);
            if("1".equals(res.getString("status"))){
                //表示查询结果正常了，接下来做处理
                if("1".equals(res.getString("count"))){
                    //表述这有确切的地点
                    String route = res.getString("route");
                    JSONObject routeArray = JSONObject.parseObject(route, JSONObject.class);
                    List<BigDecimal[]> linePoint = new ArrayList<>();
                    String paths = routeArray.getString("paths");
                    List<JSONObject> pathArray = JSONArray.parseArray(paths,JSONObject.class);
                    JSONObject jsonPath = pathArray.get(0);
                    String steps = jsonPath.getString("steps");
                    List<JSONObject> stepsArray = JSONArray.parseArray(steps,JSONObject.class);
                    for(JSONObject ele:stepsArray){
                        String polylineStr = ele.getString("polyline");
                        String[] split = polylineStr.split(";");
                        for(String str :split){
                            String[] position = str.split(",");
                            linePoint.add(new BigDecimal[]{new BigDecimal(position[0]),new BigDecimal(position[1])});
                        }
                    }
                    log.info("当前路径坐标{}",linePoint);

                    linePoint.forEach(ele ->{
                        double[] doubles = LonlatConver.gcj02_To_Wgs84(ele[0].doubleValue(), ele[1].doubleValue());
                        pam.add(new BigDecimal[]{new BigDecimal(doubles[0]+""),new BigDecimal(doubles[1]+"")});
                    });
                }
            }
        }
        return pam;
    }

    @Override
    @Cacheable(key = "'findOneArePart2:' + #enterInTime")
    public List<List<BigDecimal[]>> findOneArePart2(String enterInTime) {
        BigDecimal minlng = new BigDecimal("120.6863359794");
        BigDecimal maxlng = new BigDecimal("120.8365687032");
        BigDecimal minlat = new BigDecimal("31.3048179341");
        BigDecimal maxlat = new BigDecimal("31.3562680831");
        List<List<BigDecimal[]>> reslut = new ArrayList<>();
        RestTemplate restTemplate = new RestTemplate();
        for(int i = 0;i<30;i++){
            BigDecimal lng = RandomUtil.randomBigDecimal(minlng, maxlng);
            BigDecimal lat = RandomUtil.randomBigDecimal(minlat, maxlat);
            String origin = lng+","+lat;
            //换取参数
            ResponseEntity<String> forEntity = restTemplate.getForEntity("https://restapi.amap.com/v5/direction/driving?" +
                            "key=a55d9d3ac4c5c777f76415b080f76000" +
                            "&origin=" + origin+
                            "&destination="+DESTINATION+
                            "&strategy=35,0,37"+//速度优先
                            "&show_fields=polyline"
                    , String.class);
            if(new Integer(200).equals(forEntity.getStatusCodeValue())){
                String body = forEntity.getBody();
                JSONObject res = JSONObject.parseObject(body, JSONObject.class);
                if("1".equals(res.getString("status"))){
                    //表示查询结果正常了，接下来做处理
                    if("1".equals(res.getString("count"))){
                        //表述这有确切的地点
                        String route = res.getString("route");
                        JSONObject routeArray = JSONObject.parseObject(route, JSONObject.class);
                        List<BigDecimal[]> linePoint = new ArrayList<>();
                        String paths = routeArray.getString("paths");
                        List<JSONObject> pathArray = JSONArray.parseArray(paths,JSONObject.class);
                        JSONObject jsonPath = pathArray.get(0);
                        String steps = jsonPath.getString("steps");
                        List<JSONObject> stepsArray = JSONArray.parseArray(steps,JSONObject.class);
                        for(JSONObject ele:stepsArray){
                            String polylineStr = ele.getString("polyline");
                            String[] split = polylineStr.split(";");
                            for(String str :split){
                                String[] position = str.split(",");
                                linePoint.add(new BigDecimal[]{new BigDecimal(position[0]),new BigDecimal(position[1])});
                            }
                        }
                        log.info("当前路径坐标{}",linePoint);
                        List<BigDecimal[]> pam = new ArrayList<>();
                        linePoint.forEach(ele ->{
                            double[] doubles = LonlatConver.gcj02_To_Wgs84(ele[0].doubleValue(), ele[1].doubleValue());
                            pam.add(new BigDecimal[]{new BigDecimal(doubles[0]+""),new BigDecimal(doubles[1]+"")});
                        });
                        reslut.add(pam);
                    }else{
                        //表述这有确切的地点
                        String route = res.getString("route");
                        JSONObject routeArray = JSONObject.parseObject(route, JSONObject.class);
                        List<BigDecimal[]> linePoint = new ArrayList<>();
                        String paths = routeArray.getString("paths");
                        List<JSONObject> pathArray = JSONArray.parseArray(paths,JSONObject.class);
                        JSONObject jsonPath = pathArray.get(0);
                        String steps = jsonPath.getString("steps");
                        List<JSONObject> stepsArray = JSONArray.parseArray(steps,JSONObject.class);
                        for(JSONObject ele:stepsArray){
                            String polylineStr = ele.getString("polyline");
                            String[] split = polylineStr.split(";");
                            for(String str :split){
                                String[] position = str.split(",");
                                linePoint.add(new BigDecimal[]{new BigDecimal(position[0]),new BigDecimal(position[1])});
                            }
                        }
                        log.info("当前路径坐标{}",linePoint);
                        List<BigDecimal[]> pam = new ArrayList<>();
                        linePoint.forEach(ele ->{
                            double[] doubles = LonlatConver.gcj02_To_Wgs84(ele[0].doubleValue(), ele[1].doubleValue());
                            pam.add(new BigDecimal[]{new BigDecimal(doubles[0]+""),new BigDecimal(doubles[1]+"")});
                        });
                        reslut.add(pam);
                    }
                }
            }
        }
        return reslut;
    }

    @Override
    public Map<String,Object> findDateLimit(Pageable pageable) {
        Page<TimeLine> all = timeLineRepository.findAll(pageable);
        return PageUtil.toPage(all.map(timeLineMapper::toDto));
    }

}